#! /usr/bin/env python
#coding=utf-8

"""
    2011 Boris Tatarintsev
    
    Simple LJ user friends hierarchy 2D visualizer
"""

import pygame
import math
import random
import os
import __main__

from pygame.locals import *

class LJVisualizer:
    
    SCREEN_WIDTH = 800
    SCREEN_HEIGHT = 600
    
    def __init__(self, friendsData, windowWidth = SCREEN_WIDTH, windowHeight = SCREEN_HEIGHT):        
                
        self.m_friendsData = friendsData
        self.m_windowWidth = windowWidth
        self.m_windowHeight = windowHeight
        
        self.m_rootPos = (self.m_windowWidth / 2, self.m_windowHeight / 2)
        self.m_levelRadius = 100
        
        self.m_showLabels = False
        self.m_isAlive = True
        
        # prepare data
        self.m_rootNode = self.m_friendsData.findRoot()
        # sort nodes according to their depth property
        m_sortedNodes = []
        for level in xrange(1, self.m_friendsData.getMaxDepth()):
            m_sortedNodes.append(self.m_friendsData.filterNodesByProperty('D', level))
        # prepare coordinates
        self.m_coordinates = {}
        self.m_coordinates[self.m_rootNode] = ( (self.m_rootPos[0], self.m_rootPos[1], 0) )
        depth = 1        
        for nodes in m_sortedNodes:
            n = len(nodes)
            if n != 0:
                degStep = 2 * 3.141598 / n
            alpha = 0
            #print depth, n
            k = self.m_levelRadius * depth
            for idx in xrange(0, n):                
                node = nodes[idx]
                x = int(k * math.cos(alpha)) + self.m_rootPos[0]
                y = int(k * math.sin(alpha)) + self.m_rootPos[1]
                self.m_coordinates[node] = ( (x, y, depth) )                
                alpha += degStep
            depth += 1        
        
    def __drawNode(self, node, position, level):        
        pygame.draw.circle(self.m_screen, (100, 100, 100), position, int((1.0 / (level + 1)) * 20), 0)        
    
    def __generateCoords(self, center, innerRadius, outerRadius):
        return ( center[0] + random.randint(innerRadius, outerRadius), center[1] + random.randint(innerRadius, outerRadius) )

    def __processEvents(self): 
        for event in pygame.event.get():
            if event.type == QUIT: 
                self.m_isAlive = False
     #           pygame.quit()
                __main__.createUI()
            elif event.type == KEYDOWN:
                if(chr(event.key) == 'c' or chr(event.key) == 'C'):
                    self.m_showLabels = not self.m_showLabels
            
    def initPyGame(self):
        # initialize game window
        pygame.init()
        self.m_window = pygame.display.set_mode((self.m_windowWidth, self.m_windowHeight))
        self.m_screen = pygame.display.get_surface()
        # init fonts
        fontPath = os.path.join("font", "xsuni.ttf")
        self.bigfont = pygame.font.Font(fontPath, 40)
        self.smallfont = pygame.font.Font(fontPath, 12)
        self.verysmallfont = pygame.font.Font(fontPath, 7)        
    
    def update(self):
        if not self.m_isAlive: return
        self.__processEvents()        

    def paint(self):        
        if not self.m_isAlive: return
        self.m_screen.fill( (0, 0, 0) )                
        keys = self.m_coordinates.keys()          
        # draw other nodes level by level        
        for k in keys:
            node = self.m_coordinates[k]                    
            # draw links
            refSet = self.m_friendsData.getRefSet(k.m_name)
            if refSet != None:
                for user in refSet:
                    to_x, to_y, a = self.m_coordinates[self.m_friendsData.getNode(user)]
                    pygame.draw.line(self.m_screen, (55 ,55, 55), (node[0], node[1]), (to_x, to_y), 1)
                    
        for k in keys:
            node = self.m_coordinates[k]
            # draw nodes
            self.__drawNode(None, (node[0], node[1]), node[2])
        
        # show caption if needed                
        if self.m_showLabels:
            for k in keys:
                node = self.m_coordinates[k]
                label = self.smallfont.render(k.m_name, 1, (255, 255, 255))
                self.m_screen.blit(label, (node[0], node[1]))
        
        pygame.display.flip()
